package com.dualsportmaps.android;

import net.osmand.LogUtil;
import net.osmand.plus.activities.MapActivity;

import org.apache.commons.logging.Log;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.widget.Toast;

public class DsmMapDownloadServiceManager {
	
	private Context context;
	public DsmMapDownloadServiceManager(Context context) {
		this.context = context;
	}
	static final int MSG_REGISTER_CLIENT = 1;    
	static final int MSG_UNREGISTER_CLIENT = 2; 
	static final int MSG_MAP_DOWNLOAD = 3;
	static final int MSG_TOAST = 4;
	static final int MSG_MAP_DOWNLOAD_STARTED = 5;
	static final int MSG_PROCESS_GPX = 6;
	static final int MSG_STOP_SERVICE = 7;
	
	private static final Log log = LogUtil.getLog(DsmMapDownloadServiceManager.class);
	/** Messenger for communicating with service. */
	Messenger mService = null;
	/** Flag indicating whether we have called bind on the service. */
	boolean mIsBound;

	/**
	 * Handler of incoming messages from service.
	 */
	class IncomingHandler extends Handler {
	    @Override
	    public void handleMessage(Message msg) {
	        try {
		    	final MapActivity mapActivity = DsmResourceManager.getMapActivity();
				switch (msg.what) {
					case MSG_MAP_DOWNLOAD_STARTED:
			    	DsmResourceManager.downloadcount++;					
			        break;
				    case MSG_MAP_DOWNLOAD:
				    	final String dsmMapId = msg.getData().getString("message");
				    	log.debug("Map downloaded: " + dsmMapId);
				    	DsmResourceManager.downloadcount--;
				    	if(mapActivity != null && dsmMapId != null) {
							mapActivity.runOnUiThread(new Runnable() {
								@Override
								public void run() {
									DsmMapDownload.mapDownloadedFromWeb(dsmMapId);
								}
							});
						}
//				    	DsmMapDownload.mapDownloadedFromWeb(dsmMapId);							
				        break;
				    case MSG_PROCESS_GPX:
				    	DsmResourceManager.processcount = 0;
				    	final String gpxDsmMapId = msg.getData().getString("message");
				    	mapActivity.gpxFileLoaded(gpxDsmMapId);
				    	break;
				    case MSG_TOAST:
				    	final String toastMessage = msg.getData().getString("message");
				    	log.debug("Toast: " + toastMessage);
				    	if(mapActivity != null) {
							mapActivity.runOnUiThread(new Runnable() {
								@Override
								public void run() {
									Toast.makeText(mapActivity, toastMessage, Toast.LENGTH_LONG).show();
								}
							});
						}
				        break;
				    default:
				        super.handleMessage(msg);
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
	    }
	}

	/**
	 * Target we publish for clients to send messages to IncomingHandler.
	 */
	final Messenger mMessenger = new Messenger(new IncomingHandler());

	/**
	 * Class for interacting with the main interface of the service.
	 */
	private ServiceConnection mConnection = new ServiceConnection() {
	    public void onServiceConnected(ComponentName className,IBinder service) {
	        // This is called when the connection with the service has been
	        // established, giving us the service object we can use to
	        // interact with the service.  We are communicating with our
	        // service through an IDL interface, so get a client-side
	        // representation of that from the raw service object.
	        mService = new Messenger(service);
	        log.debug("Attached.");

	        // We want to monitor the service for as long as we are
	        // connected to it.
	        try {
	            Message msg = Message.obtain(null,
	                    MSG_REGISTER_CLIENT);
	            msg.replyTo = mMessenger;
	            mService.send(msg);
	            mIsBound = true;
	        } catch (RemoteException e) {
	            // In this case the service has crashed before we could even
	            // do anything with it; we can count on soon being
	            // disconnected (and then reconnected if it can be restarted)
	            // so there is no need to do anything here.
	        }
	        log.debug("Registered with downloader.");
	    }

	    public void onServiceDisconnected(ComponentName className) {
	        // This is called when the connection with the service has been
	        // unexpectedly disconnected -- that is, its process crashed.
	        mService = null;
	        mIsBound = false;
	        log.debug("Disconnected.");
	    }
	};

	void doBindService() {
	    // Establish a connection with the service.  We use an explicit
	    // class name because there is no reason to be able to let other
	    // applications replace our component.
		Intent serviceIntent = new Intent();
		serviceIntent.setComponent(new ComponentName("com.dualsportmaps.android", "com.dualsportmaps.android.DsmMapDownloadService"));
		context.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
	    log.debug("Binding.");
	}

	void doUnbindService() {
	    if (mIsBound) {
	        // If we have received the service, and hence registered with
	        // it, then now is the time to unregister.
	        if (mService != null) {
	            try {
	                Message msg = Message.obtain(null,MSG_UNREGISTER_CLIENT);
	                msg.replyTo = mMessenger;
	                mService.send(msg);
	            } catch (RemoteException e) {
	                // There is nothing special we need to do if the service
	                // has crashed.
	            }
	        }

	        // Detach our existing connection.
	        context.unbindService(mConnection);
	        mIsBound = false;
	        log.debug("Unbinding.");
	    }
	}

	public void downloadMapFromWeb(String dsmMapId) {
		if (mIsBound) {
	        // If we have received the service, and hence registered with
	        // it, then now is the time to unregister.
	        if (mService != null) {
	            try {
	    	        log.debug("Starting download.");
	                Message msg = Message.obtain(null,MSG_MAP_DOWNLOAD);
	                msg.replyTo = mMessenger;
	                Bundle data = new Bundle();
	                data.putString("dsmMapId", dsmMapId);
	                msg.setData(data);
	                mService.send(msg);
	            } catch (RemoteException e) {
	                // There is nothing special we need to do if the service
	                // has crashed.
	            }
	        }
	    }
	}

	public void processGPXFile(String filepath) {
		if (mIsBound) {
	        // If we have received the service, and hence registered with
	        // it, then now is the time to unregister.
	        if (mService != null) {
	            try {
	    	        log.debug("Starting GPX Processing.");
	                Message msg = Message.obtain(null,MSG_PROCESS_GPX);
	                msg.replyTo = mMessenger;
	                Bundle data = new Bundle();
	                data.putString("filepath", filepath);
	                msg.setData(data);
	                mService.send(msg);
	            } catch (RemoteException e) {
	                // There is nothing special we need to do if the service
	                // has crashed.
	            }
	        }
	    }
	}
	
	public void stopService() {
		if(DsmResourceManager.processcount <= 0 && DsmResourceManager.downloadcount <= 0)
			if (mIsBound) {
		        // If we have received the service, and hence registered with
		        // it, then now is the time to unregister.
		        if (mService != null) {
		            try {
		                Message msg = Message.obtain(null,MSG_STOP_SERVICE);
		                msg.replyTo = mMessenger;
		                mService.send(msg);
		            } catch (RemoteException e) {
		                // There is nothing special we need to do if the service
		                // has crashed.
		            }
		        }
		    }
	}
}
